﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace AtomPuzzleSolver.Model
{
    public struct Bonding
    {
        private int _X;
        private int _Y;
        public int X
        {
            get { return _X; }
            set { _X = value; }
        }
        public int Y
        {
            get { return _Y; }
            set { _Y = value; }
        }

        public Bonding(int x, int y)
        {
            _X = x;
            _Y = y;
        }

        public Bonding(Bonding b)
        {
            _X = b.X;
            _Y = b.Y;
        }

        public Bonding North
        {
            get { return GetDirection(Direction.North, 1); }
        }

        public Bonding NorthEast
        {
            get { return GetDirection(Direction.NorthEast, 1); }
        }

        public Bonding SouthEast
        {
            get { return GetDirection(Direction.SouthEast, 1); }
        }

        public Bonding South
        {
            get { return GetDirection(Direction.South, 1); }
        }

        public  Bonding SouthWest
        {
            get { return GetDirection(Direction.SouthWest, 1); }
        }

        public Bonding NorthWest
        {
            get { return GetDirection(Direction.NorthWest, 1); }
        }

        public Bonding GetDirection(Direction direction)
        {
            switch (direction)
            {
                case Direction.North:
                    return North;
                case Direction.NorthEast:
                    return NorthEast;
                case Direction.SouthEast:
                    return SouthEast;
                case Direction.South:
                    return South;
                case Direction.SouthWest:
                    return SouthWest;
                case Direction.NorthWest:
                    return NorthWest;
            }

            throw new System.InvalidOperationException();
        }

        public Bonding GetDirection(Direction direction, int n)
        {
            if (n < 0)
            {
                direction = GetOppositeDirection(direction);
                n = -n;
            }
            switch (direction)
            {
                case Direction.North:
                    return new Bonding(_X, _Y - n);
                case Direction.NorthEast:
                    return new Bonding(_X + n, _Y - (n + Utilities.IsEven(X)) / 2);
                case Direction.SouthEast:
                    return new Bonding(_X + n, _Y + (n + Utilities.IsOdd(X)) / 2);
                case Direction.South:
                    return new Bonding(_X,_Y + n);
                case Direction.SouthWest:
                    return new Bonding(_X - n, _Y + (n + Utilities.IsOdd(X)) / 2);
                case Direction.NorthWest:
                    return new Bonding(_X - n, _Y - (n + Utilities.IsEven(X)) / 2);
            }

            throw new System.InvalidOperationException();
        }

        static Direction GetOppositeDirection(Direction direction)
        {
            switch (direction)
            {
                case Direction.North:
                    return Direction.South;
                case Direction.NorthEast:
                    return Direction.SouthWest;
                case Direction.SouthEast:
                    return Direction.NorthWest;
                case Direction.South:
                    return Direction.North;
                case Direction.SouthWest:
                    return Direction.NorthEast;
                case Direction.NorthWest:
                    return Direction.SouthEast;
            }

            throw new System.InvalidOperationException();
        }

        public Bonding Rotate()
        {
            Bonding b = new Bonding();
            b = b.GetDirection(Direction.South, (_X + Utilities.IsOdd(_X)) / 2);
            b = b.GetDirection(Direction.SouthEast, (_X - Utilities.IsOdd(_X)) / 2);
            b = b.GetDirection(Direction.SouthWest, _Y);

            return b;
        }

        public Bonding Mirror()
        {
            Bonding b = new Bonding();
            b.X = _X * -1;
            b.Y = _Y;

            return b;
        }

        public static bool operator ==(Bonding left, Bonding right)
        {
            return ((left.X == right.X) && (left.Y == right.Y));
        }

        public static bool operator !=(Bonding left, Bonding right)
        {
            return !(left == right);
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Bonding))
            {
                return false;
            }
            Bonding bonding = (Bonding)obj;
            return ((bonding.X == this.X) && (bonding.Y == this.Y));
        }

        public override int GetHashCode()
        {
            return (this.X ^ this.Y);
        }

        public override string ToString()
        {
            return ("{X=" + this.X.ToString() + ",Y=" + this.Y.ToString() + "}");
        }


    }
}
